using System;
using System.Runtime.CompilerServices;
using NFreeMarker.Template;

namespace NFreeMarker.Ext.Util
{
    /**
     * Internally used by various wrapper implementations to implement model
     * caching.
     * @version $Id: ModelCache.java,v 1.9 2003/01/12 23:40:15 revusky Exp $
     * @author Attila Szegedi
     */
    public abstract class ModelCache
    {
        private bool _useCache = false;
        //private Map modelCache = null;
        //private ReferenceQueue refQueue = null;
        
        protected ModelCache()
        {
        }
        
        /**
         * Sets whether this wrapper caches model instances. Default is false.
         * When set to true, calling {@link #getInstance(object)} 
         * multiple times for the same object will return the same model.
         */
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void SetUseCache(bool useCache)
        {
        //    this.useCache = useCache;
        //    if(useCache)
        //    {
        //        modelCache = new IdentityHashMap();
        //        refQueue = new ReferenceQueue();
        //    }
        //    else
        //    {
        //        modelCache = null;
        //        refQueue = null;
        //    }
            throw new NotImplementedException();
        }
        
        public ITemplateModel GetInstance(object obj)
        {
            if (obj is ITemplateModel)
            {
                return (ITemplateModel) obj;
            }
            if (obj is ITemplateModelAdapter)
            {
                return ((ITemplateModelAdapter) obj).GetTemplateModel();
            }
            if (_useCache && IsCacheable(obj))
            {
                //ITemplateModel model = Lookup(obj);
                //if (model == null)
                //{
                //    model = Create(obj);
                //    Register(model, obj);
                //}
                //return model;

                throw new NotImplementedException();
            }
            return Create(obj);
        }

        protected abstract ITemplateModel Create(object obj);
        protected abstract bool IsCacheable(object obj);
        
        public void ClearCache()
        {
        //    if(modelCache != null)
        //    {
        //        synchronized(modelCache)
        //        {
        //            modelCache.clear();
        //        }
        //    }
            throw new NotImplementedException();
        }

        //private ITemplateModel Lookup(object obj)
        //{
        //    ModelReference reference = null;
        //    // NOTE: we're doing minimal synchronizations -- which can lead to
        //    // duplicate wrapper creation. However, this has no harmful side-effects and
        //    // is a lesser performance hit.
        //    lock (_modelCache)
        //    {
        //        reference = (ModelReference) _modelCache.get(obj);
        //    }

        //    if (reference != null)
        //    {
        //        return reference.GetModel();
        //    }

        //    return null;
        //}

        //private void Register(ITemplateModel model, object obj)
        //{
        //    lock (_modelCache)
        //    {
        //        // Remove cleared references
        //        for (;;)
        //        {
        //            ModelReference queuedRef = (ModelReference) refQueue.poll();
        //            if (queuedRef == null)
        //            {
        //                break;
        //            }
        //            _modelCache.remove(queuedRef.object);
        //        }
        //        // Register new reference
        //        _modelCache.put(obj, new ModelReference(model, obj, refQueue));
        //    }
        //}

        ///**
        // * A special soft reference that is registered in the modelCache.
        // * When it gets cleared (that is, the model became unreachable)
        // * it will remove itself from the model cache.
        // */
        //private static final class ModelReference extends SoftReference
        //{
        //    object object;

        //    ModelReference(TemplateModel ref, object object, ReferenceQueue refQueue)
        //    {
        //        super(ref, refQueue);
        //        this.object = object;
        //    }

        //    TemplateModel getModel()
        //    {
        //        return (TemplateModel) this.get();
        //    }
        //}

    }
}